﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Web.Mvc;

namespace Web.Resource
{
    /// <summary>
    /// 资源文件格式后台验证特性   
    /// <remarks>作者：陈国伟 日期：2013/07/21</remarks>
    /// </summary>
    [AttributeUsageAttribute(AttributeTargets.Method)]
    public class ResFormatAttribute : FilterAttribute, IAuthorizationFilter
    {
        /// <summary>
        /// 允许的扩展名
        /// </summary>
        private string[] extArray;

        /// <summary>
        /// 文件格式信息
        /// </summary>
        private static List<ExtFormat> FormatInfoList = new List<ExtFormat>()
        {
            new ExtFormat(".zip", new byte[] { 0x50, 0x4B }),
            new ExtFormat(".rar", new byte[] { 0x52, 0x61 }),

            new ExtFormat(".bmp", new byte[] { 0x42, 0x4D }),
            new ExtFormat(".png", new byte[] { 0x89, 0x50 }),
            new ExtFormat(".jpg", new byte[] { 0xFF, 0xD8 }),
            new ExtFormat(".gif", new byte[] { 0x47, 0x49 }),

            new ExtFormat(".doc", new byte[] { 0xD0, 0xCF }),
            new ExtFormat(".ppt", new byte[] { 0xD0, 0xCF }),
            new ExtFormat(".xls", new byte[] { 0xD0, 0xCF }),
            new ExtFormat(".docx", new byte[] { 0x50, 0x4B }),
            new ExtFormat(".pptx", new byte[] { 0x50, 0x4B }),
            new ExtFormat(".xlsx", new byte[] { 0x50, 0x4B }),
            new ExtFormat(".pdf", new byte[] { 0x25, 0x50 }),
            new ExtFormat(".rtf", new byte[] { 0x7B, 0x5C }),
          
            new ExtFormat(".swf", new byte[] { 0x43, 0x57 }),
            new ExtFormat(".flv", new byte[] { 0x46, 0x4C })
        };

        /// <summary>
        /// 匹配文件格式和自身的扩展名
        /// </summary>
        public ResFormatAttribute()
            : this(null)
        {
        }

        /// <summary>
        ///  匹配文件格式是否属于扩展名
        /// </summary>
        /// <param name="allowExts">允许的扩展名</param>
        /// <example>.txt;.doc</example>
        public ResFormatAttribute(string allowExts)
        {
            this.extArray = allowExts.Matches(@"\.\w+").Select(item => item.ToLower()).ToArray();
        }

        /// <summary>
        /// 资源扩展名权限验证
        /// </summary>
        /// <param name="filterContext">权限上下文</param>
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            int count = filterContext.HttpContext.Request.Files.Count;
            for (int i = 0; i < count; i++)
            {
                HttpPostedFileBase file = filterContext.HttpContext.Request.Files[i];
                if (file != null)
                {
                    var exts = this.extArray;
                    if (exts.Length == 0)
                    {
                        var ext = Path.GetExtension(file.FileName).ToLower();
                        exts = new string[] { ext };
                    }

                    if (this.IsFormat(file.InputStream, exts) == false)
                    {
                        // 告诉前台401
                        filterContext.Result = new HttpUnauthorizedResult();
                        break;
                    }
                }
            }
        }


        /// <summary>
        /// 获取流的前二个字节
        /// </summary>
        /// <param name="stream">流</param>
        /// <returns></returns>
        private byte[] GetStreamFormat(Stream stream)
        {
            if (stream != null)
            {
                stream.Position = 0;
                if (stream.Length > 1)
                {
                    byte[] buffer = new byte[2];
                    stream.Read(buffer, 0, buffer.Length);
                    return buffer;
                }
            }
            return new byte[] { };
        }

        /// <summary>
        /// 判断两字节数组是否相等
        /// </summary>
        /// <param name="buffer">源字节数组</param>
        /// <param name="symbolBuffer">字节数组</param>
        /// <returns></returns>
        private bool Equal(byte[] buffer, byte[] symbolBuffer)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                if (buffer[i] != symbolBuffer[i])
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 是否文件是否是某种格式
        /// </summary>
        /// <param name="stream">文件流</param>       
        /// <param name="extArray">目标格式扩展名</param>
        /// <returns></returns>
        private bool IsFormat(Stream stream, string[] extArray)
        {
            var matchItems = FormatInfoList.Where(item => extArray.Contains(item.Extension)).ToList();
            if (matchItems.Count == extArray.Length)
            {
                var buffer = this.GetStreamFormat(stream);
                return matchItems.Exists(item => this.Equal(buffer, item.FormatValue));
            }
            return true;
        }

        /// 文件格式
        /// </summary>
        private class ExtFormat
        {
            /// <summary>
            /// 格式
            /// </summary>
            public string Extension { get; private set; }

            /// <summary>
            /// 格式标识
            /// </summary>
            public byte[] FormatValue { get; private set; }

            /// <summary>
            /// 文件格式
            /// </summary>
            /// <param name="ext">格式</param>
            /// <param name="value">格式标识</param>
            public ExtFormat(string ext, byte[] value)
            {
                this.Extension = ext;
                this.FormatValue = value;
            }
        }

    }
}
